package com.aviation.sell_ticket.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.aviation.sell_ticket.config.PaymentConfig;
import com.aviation.sell_ticket.config.RabbitMQConfig;
import com.aviation.sell_ticket.mapper.OrderMapper;
import com.aviation.sell_ticket.pojo.*;
import com.aviation.sell_ticket.service.*;
import com.aviation.sell_ticket.tool.RabbitMQUtil;
import com.aviation.sell_ticket.tool.RedisUtil;
import com.aviation.sell_ticket.tool.ResultEnum;
import com.aviation.sell_ticket.tool.ResultUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.thymeleaf.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    OrderDetailsService orderDetailsService;

    @Resource
    FlightService flightService;

    @Resource
    AlipayClient alipayClient;

    @Resource
    PaymentConfig paymentConfig;

    @Resource
    OrderMapper orderMapper;

    @Resource
    CityService cityService;

    @Resource
    ModelSeatService modelSeatService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    RedissonClient redisson;//引入分布式锁

    @Resource
    RabbitMQUtil rabbitMQUtil;

    @Resource
    FlightSequenceService flightSequenceService;

    @Resource
    RefundService refundService;

    @Value("${CALLBACK}")
    private String CALLBACK;

    @Value("${FRONT_URL}")
    private String FRONT_URL;

    /**
     * 生成订单
     *
     * @param mailbox       邮箱
     * @param passengerList 乘客信息列表
     * @param flightsList   航班信息列表
     * @param userId        用户id
     * @return Map<String, Object>
     */
    @Transactional
    @Override
    public Map<String, Object> orderGenerated(String mailbox, List<Map<String, String>> passengerList, List<Map<String, Object>> flightsList, String userId,List<String> citys) throws Exception {

        //获取全部城市信息
        Map<String, Object> cityMap = cityService.getCity();
        List<Aviation_city> cityList=JSONArray.parseArray(JSON.toJSONString(cityMap.get("data")),Aviation_city.class);

        //验证城市名称
        boolean through=false;
        for (String city : citys) {
            city=city.replace("\"", "");
            for (Aviation_city aviationCity : cityList) {
                if(aviationCity.getCity_name().equals(city)){
                    through=true;
                    break;
                }
                through=false;
            }
        }

        //判断城市信息是否正确
        if(!through){
            return ResultUtil.success(ResultEnum.FLIGHT_NULL_ERROR, null);
        }

        //验证是否购买过这一趟航班
        for (Map<String, String> stringMap : passengerList) {
            //提取乘客姓名
            String name = stringMap.get("name");
            //提取乘客身份证号码
            String IDCard = stringMap.get("IDCard");
            for (Map<String, Object> flightMap : flightsList) {
                //提取航班id
                String flightId = String.valueOf(flightMap.get("flightId"));
                //提取航班出发时间
                DateTimeFormatter struct = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                LocalDate departure = LocalDate.parse(String.valueOf(flightMap.get("departure")), struct);

                //查询用户是否已经购买过此趟航班
                Aviation_order_details sameOrder = orderDetailsService.sameOrder(name, IDCard, flightId, departure);
                if (null != sameOrder) {
                    //查询航班号
                    String number = flightService.flightNumber(flightId);
                    if (null == number) {
                        return ResultUtil.success(ResultEnum.NO_SUCH_FILGHT_OR_NO_ITINREARY_AVAILABLE_TODAY, null);
                    }
                    //返回错误信息
                    List<Object> Result = new LinkedList<>();
                    Result.add(431);
                    Result.add("当前用户:" + name + ",已购买航班号:" + number + ",起飞时间为:" + departure + "的航班,单个用户只能购买这个航班的一个座位,请选择退票再次进行购买或重新选择航班");
                    return ResultUtil.success(Result, null);
                }

            }
        }

        //生成订单
        Aviation_order order = new Aviation_order();
        order.setOrder_id(IdUtil.simpleUUID());
        order.setUser_id(userId);
        order.setGeneration_time(LocalDateTime.now());
        order.setPrice(0);
        order.setPayment(0);
        order.setDeparture(citys.get(0).replace("\"", ""));
        order.setDestination(citys.get(1).replace("\"", ""));
        order.setMailbox(mailbox.replace("\"", ""));
        //添加进数据库
        Integer generatedOrder = orderMapper.generatedOrder(order);
        if (generatedOrder <= 0) {
            throw new Exception("订单添加失败");
        }

        //订单航班顺序
        Aviation_flight_sequence sequence=new Aviation_flight_sequence();

        //填充数据
        for (Map<String, Object> stringObjectMap : flightsList) {
            String flightId = String.valueOf(stringObjectMap.get("flightId"));
            String transfer=String.valueOf(stringObjectMap.get("transfer"));
            String number=String.valueOf(stringObjectMap.get("number"));

            switch (number){
                case "0":
                    sequence.setFlight_one(flightId);
                    DateTimeFormatter struct = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    sequence.setFlight_one_time(LocalDate.parse(String.valueOf(stringObjectMap.get("departure")), struct));
                    if(transfer.equals("0")){
                        sequence.setTransfer("0");
                    }else {
                        sequence.setTransfer("1");
                    }
                    break;
                case "1":
                    sequence.setFlight_two(flightId);
                    break;
                case "2":
                    sequence.setFlight_three(flightId);
                    break;
                case "3":
                    sequence.setFlight_four(flightId);
                    break;
            }
        }

        sequence.setOrder_id(order.getOrder_id());
        sequence.setSequence(IdUtil.simpleUUID());
        //向数据库新增数据
        int sequenceAdd = flightSequenceService.sequenceAdd(sequence);
        if(sequenceAdd<=0){
            throw new Exception("订单航班顺序添加失败");
        }

        //订单总价格
        double price = 0.0;

        //进行机票购买
        for (Map<String, Object> flightMap : flightsList) {

            //转换数据
            String flightId = String.valueOf(flightMap.get("flightId"));
            int modelId = Integer.parseInt(String.valueOf(flightMap.get("modelId")));
            Integer priceDifferentiation = Integer.parseInt(String.valueOf(flightMap.get("priceDifferentiation")));
            DateTimeFormatter struct = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate departure = LocalDate.parse(String.valueOf(flightMap.get("departure")), struct);

            //判断时间是否是今天或今后
            if (!departure.isAfter(LocalDate.now()) && !departure.isEqual(LocalDate.now())) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultUtil.success(ResultEnum.THE_TIME_SHOULD_BE_TODAY_OR_LATER, null);
            }

            //判断航线是否存在
            Aviation_flight flight = flightService.verifyRoute(flightId, departure);
            if (null == flight) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultUtil.success(ResultEnum.NO_SUCH_FILGHT_OR_NO_ITINREARY_AVAILABLE_TODAY, null);
            }

            //座位id
            List<String> seatExtract = new ArrayList<>();

            RLock rLock = null;
            try {
                //获取锁
                rLock = redisson.getLock(flightId + departure);
                //设置锁的等待时间与超时时间
                if (rLock.tryLock(15, 30, TimeUnit.SECONDS)) {
                    //提取剩余的座位
                    List<String> seatId = orderDetailsService.queryOrderDetails(flightId, departure, modelId, priceDifferentiation);
                    //判断是否还有座位
                    if (seatId.size() <= 0) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return ResultUtil.success(ResultEnum.NO_SEATS_AVAILABLE, null);
                    }
                    //判断是否能够买到足够的票
                    if (seatId.size() < passengerList.size()) {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return ResultUtil.success(ResultEnum.INSUFFICIENT_REMAINING_TICKETS, null);
                    }
                    //提取座位
                    for (int i = 0; i < passengerList.size(); i++) {
                        int random = (int) (Math.random() * seatId.size());
                        seatExtract.add(flightId + departure + "seat:" + seatId.get(random));
                        seatId.remove(random);
                    }
                    //锁定座位
                    for (String seat : seatExtract) {
                        redisUtil.setRidesTime(flightId + departure + "seat:" + StringUtils.substringAfter(seat, ":"), StringUtils.substringAfter(seat, ":"), (long) 60, TimeUnit.SECONDS);
                    }
                }
            } catch (Exception e) {
                return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
            } finally {
                assert rLock != null;
                rLock.unlock();
            }


            //航班座位价格
            price = price + (OrderServiceImpl.flightPrice(flight.getFlightPrice(), priceDifferentiation) * passengerList.size()) + (flight.getModel().getFuel_tax() * passengerList.size()) + (flight.getModel().getConstruction() * passengerList.size());

            //增加机票信息进入数据库
            for (int i = 0; i < passengerList.size(); i++) {
                //构建行程信息
                Aviation_order_details orderDetails = new Aviation_order_details();
                orderDetails.setDetails_id(IdUtil.simpleUUID());
                orderDetails.setPassenger_name(passengerList.get(i).get("name"));
                orderDetails.setPassenger_number(passengerList.get(i).get("IDCard"));
                orderDetails.setPassenger_phone(passengerList.get(i).get("phone"));
                orderDetails.setDeparture_date(departure);
                orderDetails.setSeat_id(StringUtils.substringAfter(seatExtract.get(i), ":"));
                orderDetails.setModel_id(modelId);
                orderDetails.setOrder_id(order.getOrder_id());
                orderDetails.setFlight_id(flightId);
                //添加数据库
                if (!orderDetailsService.InsertOrderDetails(orderDetails)) {
                    redisUtil.deleteRedisList(seatExtract);
                    throw new Exception("购买机票失败");
                }
            }

            //清除存入redis的座位信息
            redisUtil.deleteRedisList(seatExtract);
        }

        //修改订单总价格
        if (orderMapper.updateOrder(price, order.getOrder_id()) <= 0) {
            throw new Exception("价格修改失败");
        }

        //启用消息队列
        rabbitMQUtil.orderDelay(order.getOrder_id());

        return ResultUtil.success(ResultEnum.SUCCESS, order.getOrder_id());
    }


    /**
     * 超时订单修改状态
     *
     * @param msg 订单号
     */
    @RabbitListener(queues = RabbitMQConfig.ORDER_QUEUE)
    @Override
    public void changeOrderStatus(Message msg) {
        String message = new String(msg.getBody());
        Integer orderStatus = orderMapper.verifyOrderStatus(message);
        if (orderStatus > 0) {
            orderMapper.changeOrderStatus(message);
        }
    }

    /**
     * 返回个人用户所有订单
     *
     * @param userId 用户id
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> extractOrder(String userId) {
        try {
            //返回所有订单信息
            return ResultUtil.success(ResultEnum.SUCCESS, orderMapper.extractOrder(userId));
        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
    }

    /**
     * 返回订单信息
     *
     * @param userId  用户id
     * @param orderId 订单id
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> orderingInformation(String userId, String orderId) {
        try {
            //提取订单
            Aviation_order order = orderMapper.singleOrder(userId, orderId);
            if (null == order) {
                return ResultUtil.success(ResultEnum.THERE_ARE_NO_SUCH_ORDERS, null);
            }
            //查询详细订单
            List<Aviation_order_details> details = orderDetailsService.detailedOrder(orderId);
            if (details.size() <= 0) {
                return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
            }
            //查询航班信息
            for (Aviation_order_details detail : details) {
                Aviation_flight flight = flightService.singleFlight(detail.getFlight_id(), detail.getDeparture_date());
                if (null == flight) {
                    return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
                }
                Aviation_model_seat seat = modelSeatService.SeatData(flight.getModel_id(), detail.getSeat_id());
                if (null == seat) {
                    return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
                }
                detail.setSeat(seat);
                detail.setFlight(flight);
            }
            //向订单添加详细订单信息
            order.setOrderDetails(details);

            //如果订单成功，判断订单是否可以退票
            if(order.getPayment()==2){
                DateTimeFormatter struct = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                for (Aviation_order_details orderDetail : order.getOrderDetails()) {
                    //获取航班起飞时间
                    LocalDateTime flightTime=LocalDateTime.parse(orderDetail.getDeparture_date().toString()+" "+timeCorrection(orderDetail.getFlight().getArrival_time().toString()),struct);
                    //获取当前时间
                    LocalDateTime time=LocalDateTime.now();
                    //判断是否退票状态
                    if(flightTime.isBefore(time)){
                        order.setStatusOrder(1);
                        break;
                    }
                }
            }

            return ResultUtil.success(ResultEnum.SUCCESS, order);
        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
    }


    /**
     * 手动修改订单相关状态
     *
     * @param userId  用户id
     * @param orderId 订单id
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> orderStatus(String userId, String orderId) {
        try {
            //查询订单信息
            Aviation_order order = orderMapper.singleOrder(userId, orderId);
            if (null == order) {
                return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
            }

            //判断此时订单状态
            if (order.getPayment() != 0) {
                return ResultUtil.success(ResultEnum.SUCCESS, null);
            }

            //设置准确的订单过期时间
            order.setGeneration_time(order.getGeneration_time().plusMinutes(30));
            //获取当前时间
            LocalDateTime time = LocalDateTime.now();
            //判断当前时间是否大于订单过期时间
            if (time.isAfter(order.getGeneration_time())) {
                //执行订单修改
                Integer status = orderMapper.changeOrderStatus(orderId);
                if (status > 0) {
                    return ResultUtil.success(ResultEnum.SUCCESS, null);
                }
            }

            return ResultUtil.success(ResultEnum.ABNORMAL_ORDER_MODIFICATION, null);
        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
    }

    /**
     * 生成支付
     *
     * @param userId  用户id
     * @param orderId 订单id
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> orderPay(String userId, String orderId) {
        try {
            //查询订单信息
            Aviation_order order = orderMapper.singleOrder(userId, orderId);
            if (null == order) {
                return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
            }

            //判断订单是否满足支付要求
            if (order.getPayment() != 0) {
                return ResultUtil.success(ResultEnum.ORDER_DOESS_NOT_ALLOW_PAYMENT, null);
            }

            AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
            request.setReturnUrl(CALLBACK);
            //生成订单信息
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", order.getOrder_id());
            bizContent.put("total_amount", order.getPrice());
            bizContent.put("subject", "机票订单支付");
            bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
            request.setBizContent(bizContent.toString());
            //调用支付
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
            if (response.isSuccess()) {
                return ResultUtil.success(ResultEnum.SUCCESS, response.getBody());
            } else {
                return ResultUtil.success(ResultEnum.SERVER_BUSY, null);
            }
        } catch (Exception e) {
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
    }

    /**
     * 支付回调
     *
     * @param request 回调参数
     * @return Boolean
     */
    @Override
    public String paymentCallback(HttpServletRequest request) {
        try {
            Map<String, String> params = new HashMap<>();
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String paramName = parameterNames.nextElement();
                String paramValue = request.getParameter(paramName);
                params.put(paramName, paramValue);
            }

            //订单信息异常，不属于此系统订单
            if (!params.get("auth_app_id").equals(paymentConfig.APP_ID)) {
                return "redirect:"+FRONT_URL+"?state=1";
            }

            //核验订单状态
            Aviation_order order = orderMapper.verifyOrderStatusEntity(params.get("out_trade_no"));
            if(null==order){
                return "redirect:"+FRONT_URL+"?state=3";
            }else if(order.getPayment()==1){
                return "redirect:"+FRONT_URL+"?state=4";
            }else if(order.getPayment()==2){
                return "redirect:"+FRONT_URL+"?state=0";
            }

            //验签
            if (AlipaySignature.rsaCheckV1(params, paymentConfig.ALIPAY_PUBLIC_KEY, AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2)) {
                Integer statusUpdate = orderMapper.orderStatusUpdate(params.get("out_trade_no"), params.get("timestamp"),params.get("total_amount"));
                if (statusUpdate > 0) {
                    return "redirect:"+FRONT_URL+"?state=0";
                }
            }
        } catch (Exception e) {
            return "redirect:"+FRONT_URL+"?state=1";
        }
        return "redirect:"+FRONT_URL+"?state=1";
    }

    /**
     * 订单退款
     * @param userId 用户id
     * @param orderId 订单id
     * @return Map<String, Object>
     */
    @Transactional
    @Override
    public Map<String, Object> returnTicket(String userId, String orderId) {
        try {
            //查询订单
            Aviation_order order=orderMapper.singleOrder(userId,orderId);
            if(null==order){
                return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
            }else if(order.getPayment()==3){
                return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
            }

            //提取支付金额
            double refundAmount=order.getPrice();

            //查询航班顺序
            Aviation_flight_sequence sequence = flightSequenceService.sequenceQuery(orderId);
            if(null==sequence){
                return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
            }

            //查询航班
            Aviation_flight flight=flightService.verifyRoute(sequence.getFlight_one(),sequence.getFlight_one_time());
            if(null==flight){
                return ResultUtil.success(ResultEnum.ORDER_EXCEPTION, null);
            }

            //计算时间
            DateTimeFormatter struct = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime departure_time = LocalDateTime.parse(sequence.getFlight_one_time().toString() + ' ' + timeCorrection(flight.getDeparture_time().toString()), struct);
            LocalDateTime dateTime = LocalDateTime.now();
            Duration duration = Duration.between(dateTime,departure_time);
            if(duration.toHours()<6){
                return ResultUtil.success(ResultEnum.THE_CURRENT_ORDER_DOES_NOT_SUPPORT_REFUNDS, null);
            }

            //计算退款收取的手续费用
            Aviation_refund refundQuery = refundService.refundQuery(Integer.parseInt(String.valueOf(duration.toHours())));
            if(null!=refundQuery){
                refundAmount=refundAmount-(refundAmount*refundQuery.getHandling_fees());
            }

            //生成退款订单号
            String out_request_no = IdUtil.simpleUUID();

            //修改订单状态
            int orderRefund = orderMapper.orderRefund(out_request_no, order.getOrder_id());
            if(orderRefund<=0){
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultUtil.success(ResultEnum.REFUND_FALED, null);
            }

            //开始退款
            AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", order.getOrder_id());
            bizContent.put("refund_amount", refundAmount);
            bizContent.put("out_request_no", out_request_no);
            alipayRequest.setBizContent(bizContent.toString());
            JSONObject result = JSON.parseObject(alipayClient.execute(alipayRequest).getBody());
            //判断退款状态
            JSONObject alipay_trade_refund_response = JSON.parseObject(JSON.toJSONString(result.get("alipay_trade_refund_response")));
            String msg=JSON.toJSONString(alipay_trade_refund_response.get("msg")).replace("\"","");
            if(msg.equals("Success")){
                return ResultUtil.success(ResultEnum.SUCCESS,null);
            }else {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResultUtil.success(ResultEnum.REFUND_FALED, null);
            }
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultUtil.beDefeated(ResultEnum.UNKNOWN_ERROR);
        }
    }

    /**
     * 判断是否需要填补时间
     * @param Time 时间
     * @return String
     */
    public static String timeCorrection(String Time){
        if(Time.length()<6) return Time+":00";
        else return Time;
    }


    /**
     * 提取机舱价格
     *
     * @param price                此趟航班所有舱位价格
     * @param priceDifferentiation 乘客所选舱位
     * @return Double
     */
    private static Double flightPrice(Aviation_flight_price price, Integer priceDifferentiation) {
        switch (priceDifferentiation) {
            case 0:
                return price.getEconomy_price();
            case 1:
                return price.getCommercial_affairs_price();
            case 2:
                return price.getFirst_class_price();
        }
        return 0.0;
    }
}
